class_name UnitGrid
extends Node
## 功能：2D 网格布局和单元管理
## 使用：挂载到 Node 节点上，配置导出变量。
## 说明：
## 1. 单元 Unit 存放在单元格 Cell 上，所有单元格构成整个网格 Grid
## 2. 所有坐标都是局部网格坐标系
## 3. 单元 Unit 可以为 Variant 类型

## 单元格上存在单元变化（单元添加或者移除）
signal unit_changed(old_unit: Variant, new_unit: Variant)

## 由所有单元格构成的网格，第一个分量是 Vector2i 网格坐标，第二个分量是 Unit 单元
var _cells: Dictionary


func _ready() -> void:
    for grid_initializer: GridInitializer in get_children():
        if grid_initializer != null:
            add_cells(grid_initializer.get_grid())


#region 网格布局
## 判断指定局部网格坐标的单元格是否有单元（需要提前判断 is_cell_in_grid 为 true）
func is_cell_empty(coord: Vector2i) -> bool:
    return _cells.get(coord, null) == null


## 判断网格中是否存在空单元格
func has_empty_cell() -> bool:
    return _cells.keys().any(is_cell_empty)


## 获得第一个空单元格的局部网格坐标，当没有时返回无效位置 (-1, -1)
func get_first_empty_cell_coord() -> Vector2i:
    for coord: Vector2i in _cells.keys():
        if is_cell_empty(coord):
            return coord
    return Vector2i(-1, -1)


## 添加一个空单元格到指定局部网格坐标上，添加失败则返回 false
func add_cell(coord: Vector2i) -> bool:
    if is_cell_in_grid(coord):
        return false

    _cells[coord] = null
    return true


## 添加一系列空单元格到指定局部网格中，添加失败则中断添加并返回 false
func add_cells(coords: Array[Vector2i]) -> bool:
    for coord: Vector2i in coords:
        if not add_cell(coord):
            return false
    return true


## 判断指定局部网格坐标的单元格是否在网格中
func is_cell_in_grid(coord: Vector2i) -> bool:
    return _cells.has(coord)
#endregion


#region 单元管理
## 添加一个单元到指定局部网格坐标的空单元格上，添加失败则返回 false
func add_unit_to_empty_cell(unit: Variant, coord: Vector2i) -> bool:
    if unit == null or\
       not is_cell_in_grid(coord) or\
       not is_cell_empty(coord):
        return false
    
    _cells[coord] = unit
    unit_changed.emit(null, unit)
    return true


## 获得指定局部网格坐标单元格的单元（需要提前判断 is_cell_in_grid 为 true）
func get_unit(coord: Vector2i) -> Variant:
    return _cells.get(coord, null)


## 移除指定局部网格坐标单元格上的单元（网格中不会删除该单元格），移除失败则返回 false
func remove_unit_by_cell_coord(coord: Vector2i) -> bool:
    if not is_cell_in_grid(coord) or\
       is_cell_empty(coord):
        return false
    
    var old_unit = _cells[coord]
    _cells[coord] = null
    unit_changed.emit(old_unit, null)
    return true


## 移除网格中的指定单元（网格中不会删除该单元格），移除失败则返回 false
func remove_unit(unit: Variant) -> bool:
    if unit != null:
        return remove_unit_by_cell_coord(get_unit_cell_coord(unit))
    else:
        return false


## 判断指定单元是否在网格中
func is_unit_in_grid(unit: Variant) -> bool:
    if unit != null:
        return _cells.find_key(unit) != null
    else:
        return false


## 获得指定单元在网格中的局部网格坐标
func get_unit_cell_coord(unit: Variant) -> Vector2i:
    if unit != null:
        var coord = _cells.find_key(unit)
        return coord if coord != null else Vector2i(-1, -1)
    else:
        return Vector2i(-1, -1)


## 获得网格中所有的单元
func get_all_units() -> Array[Variant]:
    var units: Array[Variant]
    
    for unit: Variant in _cells.values():
        if unit != null:
            units.append(unit)
    
    return units
#endregion
